package com.hxx.common.core.wcontour.util;

import com.alibaba.fastjson.JSON;
import com.hxx.common.core.wcontour.constant.FeatureAttrConstant;
import org.geotools.data.crs.ForceCoordinateSystemFeatureResults;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.SchemaException;
import org.geotools.filter.FilterFactoryImpl;
import org.geotools.filter.text.ecql.ECQL;
import org.geotools.geojson.feature.FeatureJSON;
import org.geotools.map.FeatureLayer;
import org.geotools.map.Layer;
import org.geotools.referencing.CRS;
import org.geotools.styling.*;
import org.geotools.util.URLs;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LinearRing;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import wcontour.global.PointD;
import wcontour.global.PolyLine;
import wcontour.global.Polygon;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Feature 工具类
 *
 * @author ***
 */
public class FeatureUtil {

    private static GeometryFactory geometryFactory = new GeometryFactory();

    /**
     * shapefile 文件转SimpleFeatureCollection
     *
     * @param path
     * @return
     */
    public static SimpleFeatureCollection shpToFeatureCollection(String path) {
        File file = new File(path);
        SimpleFeatureCollection fc = null;
        try {
            ShapefileDataStore ds = new ShapefileDataStore(URLs.fileToUrl(file));
            // 设置编码，根据shp文件设置，一般中文操作系统的arcgis导出的是GBK
            Charset charset = Charset.forName("utf-8");
            ds.setCharset(charset);
            String typeName = ds.getTypeNames()[0];
            fc = ds.getFeatureSource(typeName).getFeatures();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return fc;
    }

    /**
     * FeatureCollection 转 GeoJson对象
     *
     * @param featureCollection
     * @return
     * @throws IOException
     */
    public static JSON featureToGeoJson(FeatureCollection featureCollection) throws IOException {
        // 结果生成geojson
        FeatureJSON fjson = new FeatureJSON();
        StringWriter writer = new StringWriter();
        fjson.writeFeatureCollection(featureCollection, writer);
        return JSON.parseObject(writer.toString());
    }

    /**
     * 结果转换Polygon转FeatureCollection
     *
     * @param cPolygonList
     * @return
     */
    public static FeatureCollection getFeatureCollection(List<Polygon> cPolygonList) throws SchemaException {
        if (cPolygonList == null || cPolygonList.size() == 0) {
            return null;
        }
        List<Map<String, Object>> values = new ArrayList<Map<String, Object>>();
        for (Polygon pPolygon : cPolygonList) {
            // 外圈
            LinearRing mainRing;
            Coordinate[] coordinates = new Coordinate[pPolygon.OutLine.PointList.size()];
            for (int i = 0, len = pPolygon.OutLine.PointList.size(); i < len; i++) {
                PointD ptd = pPolygon.OutLine.PointList.get(i);
                coordinates[i] = new Coordinate(ptd.X, ptd.Y);
            }
            mainRing = geometryFactory.createLinearRing(FeatureExceptionHand.isClosedLine(coordinates));

            //孔洞
            LinearRing[] holeRing = new LinearRing[pPolygon.HoleLines.size()];
            for (int i = 0; i < pPolygon.HoleLines.size(); i++) {
                PolyLine hole = pPolygon.HoleLines.get(i);
                Coordinate[] coordinates_h = new Coordinate[hole.PointList.size()];
                for (int j = 0, len = hole.PointList.size(); j < len; j++) {
                    PointD ptd = hole.PointList.get(j);
                    coordinates_h[j] = new Coordinate(ptd.X, ptd.Y);
                }
                holeRing[i] = geometryFactory.createLinearRing(FeatureExceptionHand.isClosedLine(coordinates_h));
            }
            org.locationtech.jts.geom.Polygon geo = geometryFactory.createPolygon(mainRing, holeRing);
            Map<String, Object> map = new HashMap<String, Object>();
            map.put(FeatureAttrConstant.THE_GEOM, geo);
            map.put(FeatureAttrConstant.VALUE, pPolygon.LowValue);
            values.add(map);
        }
        return FeatureClipUtil.creatFeatureCollection(values);
    }


    /**
     * 给featureCollection添加颜色和透明度
     *
     * @param featureCollection 等值面要素几何
     * @param levelProps        色阶,结构如：{0.1:"#a5f38d"}
     * @param opacity           透明度
     */
    public static Layer addShapeLayer(FeatureCollection featureCollection, Map<Double, String> levelProps, float opacity) {
        Layer layer = null;
        try {
            // 由坐标顺序引发坐标变换，这三行由于修正数据，不加的话会出现要素漏缺。
            SimpleFeatureType simpleFeatureType = (SimpleFeatureType) featureCollection.getSchema();
            String crs = CRS.lookupIdentifier(simpleFeatureType.getCoordinateReferenceSystem(), true);
            featureCollection = new ForceCoordinateSystemFeatureResults(featureCollection,
                    CRS.decode(crs, true));
            //创建样式
            StyleFactory sf = new StyleFactoryImpl();
            FilterFactory ff = new FilterFactoryImpl();
            FeatureTypeStyle fts = sf.createFeatureTypeStyle();
            for (Map.Entry entry : levelProps.entrySet()) {
                double key = (Double) entry.getKey();
                String value = (String) entry.getValue();
                Fill fill = sf.createFill(ff.literal(value), ff.literal(opacity));
                Stroke stroke = sf.createStroke(ff.literal("#ffffff"), ff.literal(0), ff.literal(0));
                Symbolizer symbolizer = sf.createPolygonSymbolizer(stroke, fill, FeatureAttrConstant.THE_GEOM);
                Rule rule = sf.createRule();
                rule.setName("dzm_" + key);
                rule.symbolizers().add(symbolizer);
                Filter filter = ECQL.toFilter("value=" + key);
                rule.setFilter(filter);
                fts.rules().add(rule);
            }
            Style style = sf.createStyle();
            style.setName("style_dzm");
            style.featureTypeStyles().add(fts);

            layer = new FeatureLayer(featureCollection, style);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return layer;
    }
}
